﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using Manutd.Models;
using Manutd.ViewModel;
using Manutd;
using System.Collections.ObjectModel;
using System.Windows.Media.Imaging;

namespace Manutd.Services
{
    public class WebScraper
    {
        #region Fields
        
        private WebScraper webScraper;
        private string baseUrl = "http://www.goal.com";

        private ObservableCollection<Article> collectionOfTen = new ObservableCollection<Article>();
        private ObservableCollection<Article> collection = new ObservableCollection<Article>();

        private HtmlNodeCollection dayNewsDivs;
        private HtmlNode lastDayNewsDiv;
        private HtmlNode nextPageNode;
        private string nextPageUrlString;

        private bool isRefreshing;
        private bool isFromBeginingOfDayNewsDivCollection = true;
        private bool isFromBeginingOfLiNodeCollection = true;
        private bool isEndOfPage = false;

        private int lastDayNewsDivsIndex;
        private int lastLiNodeIndex;

        #endregion

        private WebScraper()
        {
            this.Article = new Article();
            this.ArticleList = new ObservableCollection<Article>();
        }

        public WebScraper GetWebScraper()
        {
            if (webScraper == null)
                webScraper = new WebScraper();
            return webScraper;
        }

        #region Properties
        
        public Article Article { get; set; }
        public ObservableCollection<Article> ArticleList { get; set; }

        #endregion


        #region Public Methods
        
        public void StartScrapingArticle(string uri, string type)
        {
            if (type.Equals("single"))
                HtmlWeb.LoadAsync(uri, OnCallback1);
            else
                HtmlWeb.LoadAsync(uri, OnCallback2);
        }

        #endregion

        private void OnCallback1(object s, HtmlDocumentLoadCompleted e)
        {
            if (e.Error == null)
            {
                var htmlDoc = e.Document;

                // get div which has id = container
                var pageContainerDiv = htmlDoc.DocumentNode.SelectSingleNode("//div[@id='pagecontainer']");

                // get div which is the child element of containerDiv and has id = subpagecontainer
                var subpageContainerDiv = pageContainerDiv.SelectSingleNode("//div[@id='subpagecontainer']");

                // continue to get child div which has class = articlecontainer
                var articleContainerDiv = subpageContainerDiv.SelectSingleNode("//div[@class='articlecontainer']");

                // continue to get child div which has class = newsmain
                var newsMainDiv = articleContainerDiv.SelectSingleNode("//div[@class='newsmain']");

                // continue to get child div which has class = newsmaincontent
                var newsMainContentDiv = newsMainDiv.SelectSingleNode("//div[@class='newsmaincontent']");

                // continue to get child div which has class = newsstory
                var newsStoryDiv = newsMainContentDiv.SelectSingleNode("//div[@class='newsstory']");

                // return the newsStoryDiv's h1
                var h1Div = newsStoryDiv.SelectSingleNode("//div//h1");

                //HtmlNode articleDiv = (from articleNode in htmlDoc.DocumentNode.Descendants()
                //                       where articleNode.Name == "div"
                //                              && articleNode.Attributes["class"].Value == "newsstory"
                //                       select articleNode).FirstOrDefault();
                //var titleH1 = articleDiv.Element("h1");
                //var text = titleH1.InnerText.Trim();

                // get the title of the article
                Article.Title = h1Div.InnerText.Trim();
                //title = DataItem.Title;

                // get content of the article
                var contents = newsStoryDiv.SelectNodes("//p");

                //var content = "";
                foreach (var p in contents)
                {
                    //Article.Content += p.InnerText + "\n";
                }
            }
        }

        private void OnCallback2(object s, HtmlDocumentLoadCompleted e)
        {
            if (e.Error == null)
            {
                var htmlDoc = e.Document;

                var newsArchiveDiv = htmlDoc.DocumentNode.SelectSingleNode("//div[@id='news-archive']");

                var paginationDiv = newsArchiveDiv.SelectSingleNode(".//div[@id='pagination']");
                this.nextPageNode = paginationDiv.SelectSingleNode(".//a[@id='next-page']");
                if (this.nextPageNode != null)
                    this.nextPageUrlString = this.nextPageNode.Attributes["href"].Value;

                var dayNewsFirstChildDiv = newsArchiveDiv.SelectSingleNode("//div[@class='day-news first-child']");
                dayNewsDivs = newsArchiveDiv.SelectNodes("//div[@class='day-news']");
                this.dayNewsDivs.Prepend(dayNewsFirstChildDiv);

                // extract day-news first-child or day-news div's content
                this.TraverseDayNewsDivsCollection(dayNewsDivs, 0);

                this.ArticleList = collection;
                //this.IsRefreshing = false;
            }
        }

        private void TraverseDayNewsDivsCollection(HtmlNodeCollection dayNewsDivs, int lastIndex)
        {
            if (!isFromBeginingOfDayNewsDivCollection)
            {
                if (lastIndex + 1 == this.dayNewsDivs.Count)
                    return;
                else
                {
                    lastIndex++;
                    this.lastLiNodeIndex = 0;
                }
            }
            for (int i = lastIndex; i < dayNewsDivs.Count; i++)
            {
                this.ExtractDayNewsDiv(dayNewsDivs[i], this.collection);

                // if the lastDayNewsDivsIndex is the index of the last dayNewsDiv
                // then increase the lastDayNewsDivsIndex by using ++ operator
                // instead of asigning it to i.
                // So that you can check when all the articles in the current page is loaded
                // and now you need to move to the next page to load more articles.
                //if (this.lastDayNewsDivsIndex == this.dayNewsDivs.Count - 1)
                //    this.lastDayNewsDivsIndex++;
                //else
                this.lastDayNewsDivsIndex = i;

                if (this.lastDayNewsDivsIndex == dayNewsDivs.Count - 1)
                {
                    this.isFromBeginingOfDayNewsDivCollection = true;
                    this.isEndOfPage = true;
                    break;
                }
                else
                {
                    this.isFromBeginingOfDayNewsDivCollection = false;
                    this.isEndOfPage = false;
                }
                if (this.collectionOfTen.Count == 0)
                    break;
            }
        }

        private void ExtractDayNewsDiv(HtmlNode dayNewsDiv, ObservableCollection<Article> collection)
        {
            this.lastDayNewsDiv = dayNewsDiv;
            var dateDiv = dayNewsDiv.SelectSingleNode(".//div[@class='date']");
            var ulDiv = dayNewsDiv.SelectSingleNode(".//ul");

            var dateString = dateDiv.InnerText;
            var extractedDateString = this.DateExtracter(dateString);

            var liNodes = ulDiv.SelectNodes(".//li");

            if (this.isFromBeginingOfLiNodeCollection)
                this.ExtractLiNode(0, liNodes, extractedDateString);
            else
            {
                if (this.lastLiNodeIndex == liNodes.Count - 1)
                    return;
                this.lastLiNodeIndex++;
                this.ExtractLiNode(this.lastLiNodeIndex, liNodes, extractedDateString);
            }
        }

        private void ExtractLiNode(int index, HtmlNodeCollection liNodes, string extractedDateString)
        {
            for (var i = index; i < liNodes.Count; i++)
            {
                var node = liNodes[i];
                var imageBoxDiv = node.SelectSingleNode(".//div[@class='imgBox']");
                var articleInfoDiv = node.SelectSingleNode(".//div[@class='articleInfo']");

                // scraping article url
                var linkNode = imageBoxDiv.SelectSingleNode(".//a");
                var articleUrlString = linkNode.Attributes["href"].Value;

                // scraping image url
                var imgNode = imageBoxDiv.SelectSingleNode(".//img/@src");
                var articleImageUrlString = imgNode.Attributes[0].Value;

                //var XPath = "/html[1]/body[1]/div[1]/div[5]/div[1]/div[1]/div[3]/div[1]/div[2]/div[2]/ul[1]/li[1]/div[2]/div[3]";

                // scraping article title
                var titleNode = articleInfoDiv.SelectSingleNode(".//a/@href");
                //var titleNode = articleInfoDiv.SelectSingleNode(XPath);
                var titleString = titleNode.InnerText;

                // scraping article summary
                var summaryNode = articleInfoDiv.SelectSingleNode(".//div[@class='articleSummary']");
                var summaryString = summaryNode.InnerText;

                var ArticleItem = new Article();
                ArticleItem.Title = titleString;
                ArticleItem.Summary = summaryString;
                ArticleItem.ArticleUrl = this.baseUrl + articleUrlString;

                var uri = new Uri(articleImageUrlString, UriKind.Absolute);
                ArticleItem.Image = new BitmapImage(uri);

                //IFormatProvider culture = new System.Globalization.CultureInfo("fr-FR");
                //ArticleItem.PubDate = DateTime.Parse(extractedDateString, culture, DateTimeStyles.AssumeLocal);

                ArticleItem.PubDateString = extractedDateString;

                // package article list into pages of 10 articles
                collectionOfTen.Add(ArticleItem);

                if (i == liNodes.Count - 1)
                    this.isFromBeginingOfLiNodeCollection = true;
                else
                    this.isFromBeginingOfLiNodeCollection = false;

                if (collectionOfTen.Count == 10)
                {
                    while (collectionOfTen.Count > 0)
                    {
                        collection.Add(collectionOfTen[0]);
                        collectionOfTen.RemoveAt(0);
                    }
                    this.lastLiNodeIndex = i;
                    //if (this.lastLiNodeIndex == liNodes.Count - 1)
                    //    this.isFromBeginingOfLiNodeCollection = true;
                    //else
                    //    this.isFromBeginingOfLiNodeCollection = false;
                    break;
                }
            }
        }

        private string DateExtracter(string datestring)
        {
            datestring = datestring.Replace(",", String.Empty);

            var tokens = datestring.Split(' ');
            var date = tokens[2];
            var month = tokens[1];
            var year = tokens[3];

            switch (month)
            {
                case "January":
                    month = "01";
                    break;
                case "February":
                    month = "02";
                    break;
                case "March":
                    month = "03";
                    break;
                case "April":
                    month = "04";
                    break;
                case "May":
                    month = "05";
                    break;
                case "June":
                    month = "06";
                    break;
                case "July":
                    month = "07";
                    break;
                case "August":
                    month = "08";
                    break;
                case "September":
                    month = "09";
                    break;
                case "October":
                    month = "10";
                    break;
                case "November":
                    month = "11";
                    break;
                case "December":
                    month = "12";
                    break;
                default:
                    break;
            }

            var result = date + "/" + month + "/" + year;

            return result;
        }

        //private void OnCallback1(object s, HtmlDocumentLoadCompleted e)
        //{
        //    if (e.Error == null)
        //    {
        //        var htmlDoc = e.Document;

        //        // get div which has id = container
        //        var pageContainerDiv = htmlDoc.DocumentNode.SelectSingleNode("//div[@id='pagecontainer']");

        //        // get div which is the child element of containerDiv and has id = subpagecontainer
        //        var subpageContainerDiv = pageContainerDiv.SelectSingleNode("//div[@id='subpagecontainer']");

        //        // continue to get child div which has class = articlecontainer
        //        var articleContainerDiv = subpageContainerDiv.SelectSingleNode("//div[@class='articlecontainer']");

        //        // continue to get child div which has class = newsmain
        //        var newsMainDiv = articleContainerDiv.SelectSingleNode("//div[@class='newsmain']");

        //        // continue to get child div which has class = newsmaincontent
        //        var newsMainContentDiv = newsMainDiv.SelectSingleNode("//div[@class='newsmaincontent']");

        //        // continue to get child div which has class = newsstory
        //        var newsStoryDiv = newsMainContentDiv.SelectSingleNode("//div[@class='newsstory']");

        //        // return the newsStoryDiv's h1
        //        var h1Div = newsStoryDiv.SelectSingleNode("//div//h1");

        //        //HtmlNode articleDiv = (from articleNode in htmlDoc.DocumentNode.Descendants()
        //        //                       where articleNode.Name == "div"
        //        //                              && articleNode.Attributes["class"].Value == "newsstory"
        //        //                       select articleNode).FirstOrDefault();
        //        //var titleH1 = articleDiv.Element("h1");
        //        //var text = titleH1.InnerText.Trim();

        //        // get the title of the article
        //        Article.Title = h1Div.InnerText.Trim();
        //        //title = DataItem.Title;

        //        // get content of the article
        //        var contents = newsStoryDiv.SelectNodes("//p");

        //        //var content = "";
        //        foreach (var p in contents)
        //        {
        //            Article.Content += p.InnerText + "\n";
        //        }
        //    }
        //}

        //private void OnCallback2(object s, HtmlDocumentLoadCompleted e)
        //{
        //    if (e.Error == null)
        //    {
        //        var htmlDoc = e.Document;

        //        var contentBackgroundDiv = htmlDoc.DocumentNode.SelectSingleNode("//div[@id='contentBackground']");
        //        var pageContentDiv = contentBackgroundDiv.SelectSingleNode("//div[@id='page-content']");
        //        var middleWrapperDiv = pageContentDiv.SelectSingleNode("//div[@id='middle_wrapper']");
        //        var twoColContentByLeftNavDiv = middleWrapperDiv.SelectSingleNode("//div[@id='two_col_content_by_left_nav']");
        //        var leftColumnDiv = twoColContentByLeftNavDiv.SelectSingleNode("//div[@id='left_column']");
        //        var newsArchiveDiv = leftColumnDiv.SelectSingleNode("//div[@id='news-archive']");
        //        var dayNewsFirstChildDiv = newsArchiveDiv.SelectSingleNode("//div[@class='day-news first-child']");

        //        var dateDiv = dayNewsFirstChildDiv.SelectSingleNode("//div[@class='date']");
        //        var ulDiv = dayNewsFirstChildDiv.SelectSingleNode(".//ul");

        //        var dateString = dateDiv.InnerText;
        //        var liNodes = ulDiv.SelectNodes(".//li");

        //        //var urlList = htmlDoc.DocumentNode.SelectNodes("//a[@href='/vn/news/4884/chuy%E1%BB%83n-nh%C6%B0%E1%BB%A3ng/2013/09/05/4240227/nani-gia-h%E1%BA%A1n-th%C3%AAm-5-n%C4%83m-v%E1%BB%9Bi-man-united']");

        //        var baseUrl = "goal.com";
        //        var ArticleItem = new Article();
        //        foreach (HtmlNode node in liNodes)
        //        {
        //            var imageBoxDiv = node.SelectSingleNode(".//div[@class='imgBox']");
        //            var articleInfoDiv = node.SelectSingleNode(".//div[@class='articleInfo']");

        //            // scraping article url
        //            var linkNode = imageBoxDiv.SelectSingleNode(".//a");
        //            //var linkUrl = linkNode.GetAttributeValue("href", "not found");
        //            var linkUrl = linkNode.Attributes["href"].Value;

        //            // scraping image url
        //            var imgNode = imageBoxDiv.SelectSingleNode(".//img/@src");
        //            var imageUrl = imgNode.Attributes[0].Value;

        //            //var XPath = "/html[1]/body[1]/div[1]/div[5]/div[1]/div[1]/div[3]/div[1]/div[2]/div[2]/ul[1]/li[1]/div[2]/div[3]";

        //            // scraping article title
        //            var titleNode = articleInfoDiv.SelectSingleNode(".//a/@href");
        //            //var titleNode = articleInfoDiv.SelectSingleNode(XPath);
        //            var title = titleNode.InnerText;

        //            // scraping article summary
        //            var summaryNode = articleInfoDiv.SelectSingleNode(".//div[@class='articleSummary']");
        //            var summary = summaryNode.InnerText;

        //            ArticleItem.Title = title;
        //            ArticleItem.Summary = summary;
        //            ArticleItem.ArticleUrl = baseUrl + linkUrl;
        //            var uri = new Uri(imageUrl, UriKind.Absolute);
        //            ArticleItem.Image = new BitmapImage(uri);
        //            //ArticleItem.PubDate = DateStringParser.parse(dateString);
        //            this.ArticleList.Add(ArticleItem);
        //        }
        //    }
        //}
    }
}
